﻿using Co9320.NamaAlert;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System.Collections.Generic;
using Co9320.NamaAlert.Model;

namespace TagServiceTest
{
    
    
    /// <summary>
    ///ParserTest のテスト クラスです。すべての
    ///ParserTest 単体テストをここに含めます
    ///</summary>
	[TestClass()]
	public class ParserTest
	{


		private TestContext testContextInstance;

		/// <summary>
		///現在のテストの実行についての情報および機能を
		///提供するテスト コンテキストを取得または設定します。
		///</summary>
		public TestContext TestContext
		{
			get
			{
				return testContextInstance;
			}
			set
			{
				testContextInstance = value;
			}
		}

		#region 追加のテスト属性
		// 
		//テストを作成するときに、次の追加属性を使用することができます:
		//
		//クラスの最初のテストを実行する前にコードを実行するには、ClassInitialize を使用
		//[ClassInitialize()]
		//public static void MyClassInitialize(TestContext testContext)
		//{
		//}
		//
		//クラスのすべてのテストを実行した後にコードを実行するには、ClassCleanup を使用
		//[ClassCleanup()]
		//public static void MyClassCleanup()
		//{
		//}
		//
		//各テストを実行する前にコードを実行するには、TestInitialize を使用
		//[TestInitialize()]
		//public void MyTestInitialize()
		//{
		//}
		//
		//各テストを実行した後にコードを実行するには、TestCleanup を使用
		//[TestCleanup()]
		//public void MyTestCleanup()
		//{
		//}
		//
		#endregion

		[TestMethod]
		public void TestSentenceOnly()
		{
			string Sample = "Hello world";
			Queue<ParseElement> Exp = new Queue<ParseElement>();
			Exp.Enqueue(new ParseElement(Sample, ParseElementType.Sentence));
			Exp.Enqueue(new ParseElement(null, ParseElementType.EOF));

			TestHead(Sample, Exp);
		}

		[TestMethod]
		public void TestTagOnly()
		{
			string Sample = "[Tag0]";
			Queue<ParseElement> Exp = new Queue<ParseElement>();
			Exp.Enqueue(new ParseElement("Tag0", ParseElementType.Tag));
			Exp.Enqueue(new ParseElement(null, ParseElementType.EOF));

			TestHead(Sample,Exp);
		}

		[TestMethod]
		public void TestEmpty()
		{
			string Sample = "";
			Queue<ParseElement> Exp = new Queue<ParseElement>();
			Exp.Enqueue(new ParseElement(null, ParseElementType.EOF));

			TestHead(Sample,Exp);
		}

		[TestMethod]
		public void TestEmptyTag()
		{
			string Sample = "[]";
			Queue<ParseElement> Exp = new Queue<ParseElement>();
			Exp.Enqueue(new ParseElement("", ParseElementType.Tag));
			Exp.Enqueue(new ParseElement(null, ParseElementType.EOF));

			TestHead(Sample, Exp);
		}


		[TestMethod]
		public void TestNull()
		{
			string Sample = null;
			Queue<ParseElement> Exp = new Queue<ParseElement>();
			Exp.Enqueue(new ParseElement(null, ParseElementType.EOF));

			TestHead(Sample, Exp);
		}

		[TestMethod]
		public void TestComplex()
		{
			string Sample = "Hello [Tag0] intermediate [Tag1] world";
			Queue<ParseElement> Exp = new Queue<ParseElement>();
			Exp.Enqueue(new ParseElement("Hello ", ParseElementType.Sentence));
			Exp.Enqueue(new ParseElement("Tag0", ParseElementType.Tag));
			Exp.Enqueue(new ParseElement(" intermediate ", ParseElementType.Sentence));
			Exp.Enqueue(new ParseElement("Tag1", ParseElementType.Tag));
			Exp.Enqueue(new ParseElement(" world", ParseElementType.Sentence));
			Exp.Enqueue(new ParseElement(null, ParseElementType.EOF));

			TestHead(Sample, Exp);
		}

		[TestMethod]
		public void TestIrregularNotClose()
		{
			string Sample = "hello [Tag0][world";
			Queue<ParseElement> Exp = new Queue<ParseElement>();
			Exp.Enqueue(new ParseElement("hello ", ParseElementType.Sentence));
			Exp.Enqueue(new ParseElement("Tag0", ParseElementType.Tag));
			Exp.Enqueue(new ParseElement("world", ParseElementType.Irregular));
			Exp.Enqueue(new ParseElement(null, ParseElementType.EOF));

			TestHead(Sample, Exp);
		}

		[TestMethod]
		public void TestIrregularRightBracketOnly()
		{
			string Sample = "hello [Tag1] [Tag2] wor]]ld]";
			Queue<ParseElement> Exp = new Queue<ParseElement>();
			Exp.Enqueue(new ParseElement("hello ", ParseElementType.Sentence));
			Exp.Enqueue(new ParseElement("Tag1", ParseElementType.Tag));
			Exp.Enqueue(new ParseElement(" ", ParseElementType.Sentence));
			Exp.Enqueue(new ParseElement("Tag2", ParseElementType.Tag));
			Exp.Enqueue(new ParseElement(" wor", ParseElementType.Sentence));
			Exp.Enqueue(new ParseElement("]]ld]", ParseElementType.Irregular));
			Exp.Enqueue(new ParseElement(null, ParseElementType.EOF));

			TestHead(Sample, Exp);
		}

		[TestMethod]
		public void TestIrregularLeftDuplicate()
		{
			string Sample = "[[Tag0]";
			Queue<ParseElement> Exp = new Queue<ParseElement>();
			Exp.Enqueue(new ParseElement("[Tag0]", ParseElementType.Irregular));
			Exp.Enqueue(new ParseElement(null, ParseElementType.EOF));

			TestHead(Sample, Exp);
		}

		[TestMethod]
		public void TestWithLineBreak()
		{
			string Sample = "[tag \r\n hogehoge \r piyo \n [tag0]";

			Queue<ParseElement> Exp = new Queue<ParseElement>();
			Exp.Enqueue(new ParseElement("tag ", ParseElementType.Irregular));
			Exp.Enqueue(new ParseElement("\r\n", ParseElementType.LineBreak));
			Exp.Enqueue(new ParseElement(" hogehoge ", ParseElementType.Sentence));
			Exp.Enqueue(new ParseElement("\r", ParseElementType.LineBreak));
			Exp.Enqueue(new ParseElement(" piyo ", ParseElementType.Sentence));
			Exp.Enqueue(new ParseElement("\n", ParseElementType.LineBreak));
			Exp.Enqueue(new ParseElement(" ", ParseElementType.Sentence));
			Exp.Enqueue(new ParseElement("tag0", ParseElementType.Tag));
			Exp.Enqueue(new ParseElement(null, ParseElementType.EOF));

			TestHead(Sample, Exp);

		}

		[TestMethod]
		public void TestNullCtor()
		{
			Parser p = new Parser(null);

			ParseElement elem = p.GetElement();

			Assert.AreEqual<ParseElementType>(ParseElementType.EOF, elem.Type);
			Assert.IsNull(elem.Value);
		}


		private void TestHead(string Sample, Queue<ParseElement> Expected)
		{
			Lexer lex = new Lexer(Sample);
			Parser p = new Parser(lex);

			for (; ; )
			{
				ParseElement act = p.GetElement();
				ParseElement exp = Expected.Dequeue();

				Assert.AreEqual<ParseElementType>(exp.Type, act.Type);

				if (exp.Type != ParseElementType.EOF)
				{
					Assert.AreEqual<string>(exp.Value, act.Value);
				}
				else
				{
					Assert.IsNull(exp.Value);
					break;
				}

			}

			Assert.AreEqual<int>(0, Expected.Count);
		}


	}
}
